package com.ftwj.demo.generate.utils;

import java.sql.Connection;
import java.sql.DatabaseMetaData;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.ftwj.demo.generate.entity.ColumnInfo;
import com.ftwj.demo.generate.entity.TableInfo;
import cn.hutool.core.util.ReflectUtil;

/**
*
* <p>Title: ConnectionUtil</p>  
* <p>Description: 数据库连接工具</p>
* <p>Copyright: Copyright (c) 2020 </p>  
* <p>Company: 兰州飞天网景信息产业有限公司</p>    
* @author WangSLi
* @date 2020年3月18日 下午11:18:50
* @version V1.0
 */
public class ConnectionUtil {
	
	private static final Logger logger=LoggerFactory.getLogger(ConfigUtil.class);
    private Connection connection;
    
    public Boolean initConnection() {
        try {
            Class.forName(DriverFactory.getDriver(ConfigUtil.getConfiguration().getDatabase().getUrl()));
            String url = ConfigUtil.getConfiguration().getDatabase().getUrl();
            String username = ConfigUtil.getConfiguration().getDatabase().getUsername();
            String password = ConfigUtil.getConfiguration().getDatabase().getPassword();
            connection = DriverManager.getConnection(url, username, password);
            logger.debug("数据库连接：SUCCESS!"); 
            return true;
        } catch (ClassNotFoundException e) {
        	logger.debug("数据库连接失败：CLASSNOTFOUND!"); 
        } catch (SQLException e) {
        	logger.debug("数据库连接失败：SQLEXCEPTION!"); 
        }
        return false;
    }
	
	/**
     * 
     * <p>Title: getMetaData</p>  
     * <p>Description: 获取所有表信息</p>  
     * @return
     * @throws SQLException 
     * @author WangsLi
     * @date 2020年3月3日  
     * @version 1.0
     */
    public List<TableInfo> getTables() throws SQLException {
    	/**
    	 * getTables(catalog, schema, tableNamePattern, types);
    	 * String catalog 包含目录名称的 String；对此参数提供 Null 值表示无需使用目录名称。
　　		 * String schema 包含架构名称模式的 String 值；对此参数提供 Null 值表示无需使用架构名称。
		 * String tableNamePattern 包含表名称模式的 String。
		 * Object[] types 含有要包含的表类型的字符串数组；Null 表示应包含所有表类型。
    	 */
        //获取数据库的元数据
    	DatabaseMetaData metaData=connection.getMetaData();
    	logger.debug("数据库地址: {}", metaData.getURL()); 
    	logger.debug("当前的用户: {}", metaData.getUserName()); 
    	logger.info("文件生成中:请勿中断程序！");   
    	String database=ReflectUtil.getFieldValue(metaData, "database").toString();
    	List<TableInfo> tables=new ArrayList<>();
    	ResultSet resultSet=metaData.getTables(database, database, "%", new String[]{"TABLE"});
    	while(resultSet.next()) {
    		String tableName=resultSet.getString("TABLE_NAME");
    		List<ColumnInfo> columns=getColumns(tableName);
			TableInfo table=new TableInfo(tableName,columns);
    		tables.add(table);
    	}
    	logger.info("文件生成位置未配置文件中已配置的位置！"); 
    	return tables;
    }
    
    /**
     * 
     * <p>Title: getMetaData</p>  
     * <p>Description: 获取指定表信息</p>  
     * @return
     * @throws SQLException 
     * @author WangsLi
     * @date 2020年3月3日  
     * @version 1.0
     */
    public List<TableInfo> getTables(List<String> tableNames) throws SQLException {
        //获取数据库的元数据
    	DatabaseMetaData metaData=connection.getMetaData();
    	logger.debug("数据库地址: {}", metaData.getURL()); 
    	logger.debug("当前的用户: {}", metaData.getUserName());   
    	logger.info("文件生成中:请勿中断程序！");  
    	String database=ReflectUtil.getFieldValue(metaData, "database").toString();
    	List<TableInfo> tables=new ArrayList<>();
    	for(String tableName:tableNames) {
    		ResultSet resultSet=metaData.getTables(database, database, tableName, new String[]{"TABLE"});
    		while(resultSet.next()) {
    			List<ColumnInfo> columns=getColumns(tableName);
    			TableInfo table=new TableInfo(tableName,columns);
    			tables.add(table);
    		}
    	}
    	return tables;
    }
    
    /**
     * 
     * <p>Title: getColumns</p>  
     * <p>Description: 获取所有表的列信息</p>  
     * @param tableName
     * @return
     * @throws SQLException 
     * @author WangSLi
     * @date 2020年3月18日  
     * @version 1.0
     */
    public List<ColumnInfo> getColumns(String tableName) throws SQLException {
    	/**
    	 * getColumns(catalog, schemaPattern, tableNamePattern, columnNamePattern);
    	 * String catalog 类别名称；它必须与存储在数据库中的类别名称匹配；该参数为 "" 表示获取没有类别的那些描述；为 null 则表示该类别名称不应该用于缩小搜索范围。
 		 * String schemaPattern 模式名称的模式；它必须与存储在数据库中的模式名称匹配；该参数为 "" 表示获取没有模式的那些描述；为 null 则表示该模式名称不应该用于缩小搜索范围。
 		 * String tableNamePattern 表名称模式；它必须与存储在数据库中的表名称匹配。
 		 * String columnNamePattern 列名称模式；它必须与存储在数据库中的列名称匹配。
    	 * catalog 
    	 */
    	DatabaseMetaData metaData=connection.getMetaData();
    	String database=ReflectUtil.getFieldValue(metaData, "database").toString();
    	List<ColumnInfo> columns=new ArrayList<>();
    	List<String> primaryKeys=new ArrayList<>();
    	ResultSet resultSet=connection.getMetaData().getPrimaryKeys(database, "%", tableName);
    	while(resultSet.next()) {
    		String columnName=resultSet.getString("COLUMN_NAME"); //列名
    		primaryKeys.add(columnName);
    	}
    	resultSet=metaData.getColumns(database, database, tableName, "%");
    	while(resultSet.next()) {
    		String columnName=resultSet.getString("COLUMN_NAME"); //列名
    		String typeName=resultSet.getString("TYPE_NAME"); //类型
    		String remarks=resultSet.getString("REMARKS"); //注释
    		ColumnInfo column=new ColumnInfo(columnName,typeName,primaryKeys.contains(columnName),remarks);
    		columns.add(column);
    	}
    	return columns;
    }


    /**
     * <p>Title: close</p>  
     * <p>Description: 关闭连接</p>   
     * @author WangsLi
     * @date 2020年2月28日  
     * @version 1.0
     */
    public void close() {
        try {
            if (!connection.isClosed()) {
                connection.close();
            }
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }
    
    public static void main(String[] args) throws SQLException {
    	ConnectionUtil connect=new  ConnectionUtil();
		if(connect.initConnection()) {
			connect.getTables();
		}
		connect.close();
	}
}
